package com.xiaoshuidi.cloud.module.rooms.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.framework.common.exception.ErrorCode;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.module.contract.api.ContractApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.RoomContractInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.RoomTenantsInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.controller.admin.roomel.vo.*;
import com.xiaoshuidi.cloud.module.rooms.convert.roomel.RoomelConvert;
import com.xiaoshuidi.cloud.module.rooms.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.rooms.enums.RentStatusEnum;
import com.xiaoshuidi.cloud.module.rooms.enums.RoomTypeEnum;
import com.xiaoshuidi.cloud.module.rooms.framework.rule.EsDeptDataPermissionRule;
import com.xiaoshuidi.cloud.module.rooms.pojo.roomel.RoomelEntity;
import com.xiaoshuidi.cloud.module.rooms.service.IRoomelService;
import com.xiaoshuidi.cloud.module.rooms.service.RoomelEsclientService;
import com.xiaoshuidi.cloud.module.system.api.dict.DictDataApi;
import com.xiaoshuidi.cloud.module.system.api.dict.dto.DictDataRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedTopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zxp.esclientrhl.enums.AggsType;
import org.zxp.esclientrhl.repository.ElasticsearchTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;

import static com.xiaoshuidi.cloud.module.rooms.pojo.roomel.RoomelEntityMapping.IsStop;

/**
 * @Author: lss
 * @CreateTime: 2023-04-27 08:45
 * @Version: 1.0
 */
@Slf4j
@Service
public class RoomelServiceImpl implements IRoomelService {

    @Autowired
    private RoomelEsclientService roomelEsclientService;

//    @Autowired
//    private RoomHouseService roomHouseService;

    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    EsDeptDataPermissionRule dataPermissionRule;

    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private ContractApi contractApi;

    @Override
    public Boolean listadd(List<RoomelCreateReqVO> roomelCreateReqVOList) {
        log.info("进入，房源信息es-批量新增...");
//        log.info("接收到的参数为："+roomelCreateReqVOList.toString());
        List<RoomelEntity> roomelEntityList = RoomelConvert.INSTANCE.convertList(roomelCreateReqVOList);
//        log.info("转换后的参数为："+roomelEntityList.toString());
        log.info("房源信息es-转换成功DO实体类...");
        try {
            BulkResponse result = roomelEsclientService.save(roomelEntityList);

            //true:全部成功  false:有失败的
            Boolean resultflag = !result.hasFailures();

            if (!resultflag) {
                log.error("同步推送es失败");
                throw new ServiceException(new ErrorCode(100351, "房源创建失败,请联系管理员~"));
            }

            log.info("房源信息es-批量新增结果:" + resultflag);
            return resultflag;

        } catch (Exception e) {
            log.error("房源信息推送es接口-批量新增:报错", e);
            throw new ServiceException(new ErrorCode(100351, "房源创建失败,请联系管理员~"));
        }
    }

    @Override
    public Boolean deleteByesid(String id) {

        boolean result = false;
        try {
            result = roomelEsclientService.deleteById(id);
        } catch (Exception e) {
            log.error("房源信息推送es接口-根据es的id删除房源:报错", e);
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public Boolean updateCover(RoomelUpdateReqVO roomelUpdateReqVO) {

        if (ObjectUtil.isEmpty(roomelUpdateReqVO.getId())) {
            log.error("传入的id不能为空！");
            throw new IllegalArgumentException("传入的id不能为空！");
        }

        log.info("接收到的参数为：" + roomelUpdateReqVO);

        RoomelEntity roomelEntity = RoomelConvert.INSTANCE.convert(roomelUpdateReqVO);

        boolean result = false;
        try {
            result = elasticsearchTemplate.update(roomelEntity);
        } catch (Exception e) {
            log.error("房源信息推送es接口-根据es的id更新房源:报错", e);
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public Boolean updateCoverBatch(List<RoomelUpdateReqVO> reqVOList) {
        if (ObjectUtil.isEmpty(reqVOList)) {
            return Boolean.FALSE;
        }
        // List<RoomelEntity> list = MyRoomelConvert.RoomelUpdateReqVOToRoomelEntity(reqVOList);
        List<RoomelEntity> list = RoomelConvert.INSTANCE.convertList4(reqVOList);
        boolean result = false;
        try {
            BulkResponse ret = elasticsearchTemplate.bulkUpdate(list);
            //true:全部成功  false:有失败的
            result = !ret.hasFailures();
        } catch (Exception e) {
            log.error("房源信息推送es接口-根据es的id更新房源:报错", e);
            throw new RuntimeException(e);
        }
        return result;

    }

    @Override
    public List<RoomelEntity> getRoomelList(Long[] ids, Long tenantId) {
        List<RoomelEntity> search = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termsQuery("id", ids))
                    .must(QueryBuilders.termQuery(IsStop, false))
                    .must(QueryBuilders.matchQuery("tenantId", tenantId));
            searchSourceBuilder.query(queryBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = elasticsearchTemplate.search(searchRequest);
            long value = searchResponse.getHits().getTotalHits().value;
            if (value > 0) {
                SearchHit[] hits = searchResponse.getHits().getHits();
                Arrays.stream(hits).forEach(hit -> {
                    RoomelEntity roomelEntity = JSONObject.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                    search.add(roomelEntity);
                });
            }
        } catch (Exception e) {
            log.error("房源信息推送es接口-全查询:报错", e);
            throw new RuntimeException(e);
        }
        return search;

    }

    @Override
    public CommonResult<PageResult<RoomelQueryResp>> queryPage(RoomelQueryReqVO reqVO, Long tenantId) {
        log.info("进入-房源信息es接口-分页查询service");
        List<RoomelQueryResp> roomelQueryResps = new ArrayList<>();

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));

        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, reqVO);

        searchSourceBuilder.query(queryBuilder);
        //排序
        searchSourceBuilder.sort("apartmentAreaName" + ".sort", SortOrder.ASC);
        searchSourceBuilder.sort("buildingNo" + ".sort", SortOrder.ASC);
        searchSourceBuilder.sort("roomHouseName" + ".sort", SortOrder.ASC);
        //分页
        searchSourceBuilder.from((reqVO.getPageNo() - 1) * reqVO.getPageSize());
        searchSourceBuilder.size(reqVO.getPageSize());
        if (((reqVO.getPageNo() - 1) * reqVO.getPageSize()) + reqVO.getPageSize() > 10000) {
            throw new ServiceException(new ErrorCode(20010, "请根据条件筛选，缩小查询范围"));
        }
        searchRequest.source(searchSourceBuilder);
        long total = 0;
        int i = 0;
        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            log.info("房源信息es接口-分页查询语句:{}", searchRequest.source().toString());
            SearchHits searchHits = searchResponse.getHits();
            // 共有多少条数据
            total = searchHits.getTotalHits().value;
            for (SearchHit hit : searchHits.getHits()) {
                i++;
                RoomelEntity roomelEntity = JSONObject.parseObject(hit.getSourceAsString(), RoomelEntity.class);
                RoomelQueryResp queryResp = RoomelConvert.INSTANCE.convert(roomelEntity);
                if(StrUtil.isNotEmpty(roomelEntity.getTenantinfo())){
                    RoomTenantsInfoDTO roomTenantsInfoDTO = JsonUtils.parseObject(roomelEntity.getTenantinfo(), RoomTenantsInfoDTO.class);
                    // 优先显示公司名
                    queryResp.setTenantName(ObjectUtil.isNotEmpty(roomTenantsInfoDTO.getCompanyName()) ? roomTenantsInfoDTO.getCompanyName() : roomTenantsInfoDTO.getName());
                }
                if(StrUtil.isNotEmpty(roomelEntity.getContractInfo())){
                    RoomContractInfoDTO roomContractInfoDTO = JsonUtils.parseObject(roomelEntity.getContractInfo(), RoomContractInfoDTO.class);
                    queryResp.setExpiryDate(roomContractInfoDTO.getExpiryDate());
                    queryResp.setLeaseRenewalExpiryDate(roomContractInfoDTO.getLeaseRenewalExpiryDate());
                }
                roomelQueryResps.add(queryResp);
            }
        } catch (Exception e) {
            System.out.println("i = " + i);
            log.error("房源信息推送es接口-分页查询:报错", e);
            throw new RuntimeException(e);
        }

        return CommonResult.success(new PageResult<>(roomelQueryResps, total));
    }

    @Override
    public Map<String, Object> queryHouseStateSum(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, Integer floorNo, Long roomHouseTypeId,
                                                  Long layoutId, String houseState, String searchbox, String roomUsage,Boolean qflag, Long tenantId) {

        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setRoomUsage(roomUsage);
        roomelQueryReqVO.setQflag(qflag);

        Map<String, Object> ret = new HashMap<>();

        Map search = new HashMap();
        Map searchUsage = new HashMap();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);

        //因为房源类型不受houseState影响，所以每次房源类型查询时不加houseState条件
        BoolQueryBuilder queryBuilder1 = QueryBuilders.boolQuery();
        queryBuilder1.must(QueryBuilders.termQuery("tenantId", tenantId));
        roomelQueryReqVO.setHouseState(null);
        roomelQueryReqVO.setRoomUsage(null);
        queryBuilder1 = addRoomFilter(queryBuilder1, roomelQueryReqVO);
        try {
            search = roomelEsclientService.aggs("id", AggsType.count, queryBuilder, "houseState.keyword");
            searchUsage = roomelEsclientService.aggs("id", AggsType.count, queryBuilder1, "roomUsage.keyword");
        } catch (Exception e) {
            log.error("Es房态计数查询报错！", e);
            throw new RuntimeException(e);
        }
        Map search1 = new HashMap();
        BoolQueryBuilder boolQueryBuilder = queryBuilder.filter(QueryBuilders.termQuery("isClean", false));
        try {
            search1 = roomelEsclientService.aggs("id", AggsType.count, boolQueryBuilder,"isClean");
        } catch (Exception e) {
            log.error("Es脏净房计数查询报错！", e);
            throw new RuntimeException(e);
        }

        //添加维修房数量统计条件
        /*Map search2 = new HashMap();
        BoolQueryBuilder queryBuilder2 = QueryBuilders.boolQuery();
        queryBuilder2.must(QueryBuilders.termQuery("tenantId", tenantId));
        queryBuilder2 = addRoomFilter(queryBuilder2, roomelQueryReqVO);
        BoolQueryBuilder boolQueryBuilder2 = queryBuilder2.filter(QueryBuilders.termQuery("isRepair", true));
        try {
            search2 = roomelEsclientService.aggs("id", AggsType.count, boolQueryBuilder2,"isRepair");
        } catch (Exception e) {
            log.error("Es维修房计数查询报错！", e);
            throw new RuntimeException(e);
        }*/

        //获取房源类型的字段值
        Long searchUsagesumval = 0L;
        CommonResult<List<DictDataRespDTO>> dictDataByType = dictDataApi.getDictDataByType("house_types");
        if (CollectionUtils.isNotEmpty(dictDataByType.getData())){
            for (DictDataRespDTO dictDataRespDTO : dictDataByType.getData()) {
                Object searchUsageVal = searchUsage.get(dictDataRespDTO.getValue());
                if (ObjectUtil.isNotEmpty(searchUsageVal)) {
                    ret.put(dictDataRespDTO.getLabel(), searchUsageVal);
                    searchUsagesumval += (Long) searchUsageVal;
                } else {
                    ret.put(dictDataRespDTO.getLabel(), 0L);
                }
            }
        }

        //封装 根据房态枚举类，来自动封装Map
        log.info("根据房态枚举类，来自动封装Map----------");
        RentStatusEnum[] values = RentStatusEnum.values();
        Long sumval = 0L;
        Long allCheckIn = 0L;
        for (RentStatusEnum value : values) {
            Object searchval = search.get(value.getValue());
            if (ObjectUtil.isNotEmpty(searchval)) {
                ret.put(value.getValue(), searchval);
                sumval += (Long) searchval;
            } else {
                ret.put(value.getValue(), 0L);
            }
            if (value.getValue().equals(RentStatusEnum.STAYINGIN.getValue())
                    || value.getValue().equals(RentStatusEnum.CHECKEDIN.getValue()) || value.getValue().equals(RentStatusEnum.OVERDUE.getValue())) {
                allCheckIn += (searchval == null ? 0l : (long) searchval);
            }
        }
        Object clean = search1.get(0L);
        if(ObjectUtil.isNotEmpty(clean)){
            ret.put("isClean",clean);
            sumval += (Long) clean;
        }
        /*Object repair = search2.get(1L);
        if(ObjectUtil.isNotEmpty(repair)){
            ret.put("isRepair",repair);
            sumval += (Long) repair;
        }*/
        ret.put("allsum", searchUsagesumval);
        ret.put("allRoomUsageSum", searchUsagesumval);
        ret.put("allCheckIn", allCheckIn);
        double checkInRate = 0d;
        if (sumval != 0 && allCheckIn != 0) {
            checkInRate = BigDecimal.valueOf(allCheckIn).divide(BigDecimal.valueOf(sumval), 4, RoundingMode.HALF_UP).doubleValue();
        }
        ret.put("checkInRate", checkInRate);

        //出租率
        if (checkInRate == 0d){
            ret.put("rentalRate", "0%");
        }else {
            DecimalFormat df = new DecimalFormat("#.##");
            String formattedResult = df.format(checkInRate * 100);
            ret.put("rentalRate", formattedResult + "%");
        }
//        // 出租率 = 已生效合同房间/总房间数   已生效合同房间=合同状态为生效中且合同开始时间小于等于今天
//        try {
//            Long totalRoomNum = 0L;
//            for (Object key : search.keySet()) {
//                Long num = (Long) search.get(key);
//                totalRoomNum += num;
//            }
//            CommonResult<List<Long>> activeContractRooms = contractApi.getActiveContractRooms(apartmentId);
//            activeContractRooms.checkError();
//            List<Long> data = activeContractRooms.getData();
//            Long size = (long)data.size();
//            if (totalRoomNum == 0L){
//                ret.put("rentalRate", "0%");
//            }else {
//                double result = (double) size / totalRoomNum;
//                double roundedNumber = NumberUtil.round(result * 100.0, 1).doubleValue();
//                DecimalFormat df = new DecimalFormat("#.#");
//                String formattedResult = df.format(roundedNumber);
//                ret.put("rentalRate", formattedResult+"%");
//            }
//        } catch (Exception e) {
//            log.error("计算出租率异常，",e);
//            ret.put("rentalRate", "0%");
//        }

        return ret;
    }

    @Override
    public List<QueryBuildingNoRespVO> queryBuildingNoSum(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, Integer floorNo, Long roomHouseTypeId,
                                                          Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {
        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryBuildingNoRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        TermsAggregationBuilder buildingGroupAgg = AggregationBuilders.terms("buildingGroup").field("buildingNo" + ".sort").size(pageNum * pageSize).order(BucketOrder.key(true));
        buildingGroupAgg.subAggregation(AggregationBuilders.topHits("buildingInfo").fetchSource(new String[]{"buildingNo"}, null).size(1));
        searchSourceBuilder.aggregation(buildingGroupAgg);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms buildingGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("buildingGroup");
            buildingGroupTerms.getBuckets().stream().forEach(bucket -> {
                ParsedTopHits buildingInfoTopHits = (ParsedTopHits) bucket.getAggregations().getAsMap().get("buildingInfo");
                for (SearchHit hit : buildingInfoTopHits.getHits().getHits()) {
                    QueryBuildingNoRespVO queryXqTabRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryBuildingNoRespVO.class);
                    respVOS.add(queryXqTabRespVO);
                }
            });

        } catch (Exception e) {
            log.error("动态加载楼栋选项卡报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    @Override
    public List<QueryFloorTabRespVO> queryFloorTab(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, String unitNo, Integer floorNo, Long roomHouseTypeId,
                                                   Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {

        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);
        roomelQueryReqVO.setUnitNo(unitNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryFloorTabRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        TermsAggregationBuilder floorNoGroupAgg = AggregationBuilders.terms("floorNoGroup").field("floorNo").size(pageNum * pageSize).order(BucketOrder.key(true));
        floorNoGroupAgg.subAggregation(AggregationBuilders.topHits("floorNoInfo").fetchSource(new String[]{"floorNo"}, null).size(1));
        searchSourceBuilder.aggregation(floorNoGroupAgg);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms floorNoGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("floorNoGroup");
            floorNoGroupTerms.getBuckets().stream().forEach(bucket -> {
                ParsedTopHits floorNoInfoTopHits = (ParsedTopHits) bucket.getAggregations().getAsMap().get("floorNoInfo");
                for (SearchHit hit : floorNoInfoTopHits.getHits().getHits()) {
                    QueryFloorTabRespVO queryFloorTabRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryFloorTabRespVO.class);
                    respVOS.add(queryFloorTabRespVO);
                }
            });
        } catch (Exception e) {
            log.error("动态加载楼层选项卡查询报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    @Override
    public List<QueryFxTabRespVO> queryFxTab(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, Integer floorNo, Long roomHouseTypeId,
                                             Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {
        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryFxTabRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));

        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        TermsAggregationBuilder layoutGroupAgg = AggregationBuilders.terms("layoutGroup").field("layoutId").size(pageNum * pageSize).order(BucketOrder.key(true));
        layoutGroupAgg.subAggregation(AggregationBuilders.topHits("layoutInfo").fetchSource(new String[]{"layoutId", "layoutName"}, null).size(1));
        searchSourceBuilder.aggregation(layoutGroupAgg);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms layoutGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("layoutGroup");
            layoutGroupTerms.getBuckets().stream().forEach(bucket -> {
                ParsedTopHits layoutInfoTopHits = (ParsedTopHits) bucket.getAggregations().getAsMap().get("layoutInfo");
                for (SearchHit hit : layoutInfoTopHits.getHits().getHits()) {
                    QueryFxTabRespVO queryFxTabRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryFxTabRespVO.class);
                    respVOS.add(queryFxTabRespVO);
                }
            });
        } catch (Exception e) {
            log.error("动态加载房型选项卡查询报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    @Override
    public List<QueryHxTabRespVO> queryHxTab(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, Integer floorNo, Long roomHouseTypeId,
                                             Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {

        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryHxTabRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));

        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        TermsAggregationBuilder roomHouseTypeGroupAgg = AggregationBuilders.terms("roomHouseTypeGroup").field("roomHouseTypeId").size(pageNum * pageSize).order(BucketOrder.key(true));
        roomHouseTypeGroupAgg.subAggregation(AggregationBuilders.topHits("roomHouseTypeInfo").fetchSource(new String[]{"roomHouseTypeId", "roomHouseTypeName"}, null).size(1));
        searchSourceBuilder.aggregation(roomHouseTypeGroupAgg);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms roomHouseTypeGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("roomHouseTypeGroup");
            roomHouseTypeGroupTerms.getBuckets().stream().forEach(bucket -> {
                ParsedTopHits roomHouseTypeInfoTopHits = (ParsedTopHits) bucket.getAggregations().getAsMap().get("roomHouseTypeInfo");
                for (SearchHit hit : roomHouseTypeInfoTopHits.getHits().getHits()) {
                    QueryHxTabRespVO queryHxTabRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryHxTabRespVO.class);
                    respVOS.add(queryHxTabRespVO);
                }
            });
        } catch (Exception e) {
            log.error("动态加载户型选项卡查询报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    /**
     * 动态选项卡-小区查询
     **/
    @Override
    public List<QueryXqTabRespVO> queryXqTab(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, Integer floorNo, Long roomHouseTypeId,
                                             Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {

        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryXqTabRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);


        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);

        TermsAggregationBuilder roomAreaIdGroup = AggregationBuilders.terms("roomAreaIdGroup").field("roomAreaId").size(pageNum * pageSize).order(BucketOrder.key(true));
        roomAreaIdGroup.subAggregation(AggregationBuilders.topHits("roomAreaInfo").fetchSource(new String[]{"apartmentAreaId", "apartmentAreaName", "roomAreaId"}, null).size(1));
        searchSourceBuilder.aggregation(roomAreaIdGroup);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms roomAreaIdGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("roomAreaIdGroup");
            roomAreaIdGroupTerms.getBuckets().forEach(roomAreaIdGroupBucket -> {
                ParsedTopHits roomAreaInfoTopHits = (ParsedTopHits) roomAreaIdGroupBucket.getAggregations().getAsMap().get("roomAreaInfo");
                for (SearchHit hit : roomAreaInfoTopHits.getHits().getHits()) {
                    QueryXqTabRespVO queryXqTabRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryXqTabRespVO.class);
                    respVOS.add(queryXqTabRespVO);
                }
            });
        } catch (Exception e) {
            log.error("动态加载小区选项卡查询报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    @Override
    public RoomelEntity queryById(Long id, Long tenantId) {
        RoomelEntity roomelEntity = null;
        try {
            SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.termQuery("id", id))
                    .must(QueryBuilders.termQuery(IsStop, false))
                    .must(QueryBuilders.termQuery("tenantId", tenantId));
            searchSourceBuilder.query(queryBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = elasticsearchTemplate.search(searchRequest);
            long value = searchResponse.getHits().getTotalHits().value;
            if (value > 0) {
                SearchHit hit = searchResponse.getHits().getHits()[0];
                roomelEntity = JSONObject.parseObject(hit.getSourceAsString(), RoomelEntity.class);
            }
        } catch (Exception e) {
            log.error("房源信息推送es接口-全查询:报错", e);
            throw new RuntimeException(e);
        }
        return roomelEntity;
    }

    @Override
    public List<QueryUnitNoRespVO> queryUnitNoSum(Long roomAreaId, Long apartmentAreaId, String apartmentAreaName, Long apartmentId, String buildingNo, String unitNo, Integer floorNo, Long roomHouseTypeId, Long layoutId, String houseState, String searchbox, Boolean qflag, Long tenantId, Integer pageNum, Integer pageSize) {

        RoomelQueryReqVO roomelQueryReqVO = new RoomelQueryReqVO();
        //存值
        roomelQueryReqVO.setRoomAreaId(roomAreaId);
        roomelQueryReqVO.setApartmentAreaId(apartmentAreaId);
        roomelQueryReqVO.setApartmentAreaName(apartmentAreaName);
        roomelQueryReqVO.setApartmentId(apartmentId);
        roomelQueryReqVO.setBuildingNo(buildingNo);
        roomelQueryReqVO.setUnitNo(unitNo);

        roomelQueryReqVO.setFloorNo(floorNo);
        roomelQueryReqVO.setRoomHouseTypeId(roomHouseTypeId);
        roomelQueryReqVO.setLayoutId(layoutId);

        roomelQueryReqVO.setHouseState(houseState);
        roomelQueryReqVO.setSearchbox(searchbox);
        roomelQueryReqVO.setQflag(qflag);

        List<QueryUnitNoRespVO> respVOS = new ArrayList<>();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("tenantId", tenantId));
        queryBuilder.must(QueryBuilders.existsQuery("unitNo.keyword"));
        //封装筛选条件
        queryBuilder = addRoomFilter(queryBuilder, roomelQueryReqVO);
        // 单元号不能为 null 和 ""
        BoolQueryBuilder builder = QueryBuilders.boolQuery()
                .must(queryBuilder)
                .must(QueryBuilders.boolQuery()
                        .mustNot(QueryBuilders.termQuery("unitNo.keyword", "")));

        SearchRequest searchRequest = new SearchRequest(ApiConstants.ROOMELENTIRY);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(builder);

        TermsAggregationBuilder unitNoGroup = AggregationBuilders.terms("unitNoGroup").field("unitNo" + ".keyword").size(pageNum * pageSize).order(BucketOrder.key(true));
        unitNoGroup.subAggregation(AggregationBuilders.topHits("unitInfo").fetchSource(new String[]{"unitNo"}, null).size(1));
        searchSourceBuilder.aggregation(unitNoGroup);
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse searchResponse = roomelEsclientService.search(searchRequest);
            ParsedTerms unitNoGroupTerms = (ParsedTerms) searchResponse.getAggregations().getAsMap().get("unitNoGroup");
            unitNoGroupTerms.getBuckets().forEach(unitNoGroupBucket -> {
                ParsedTopHits unitInfoTopHits = (ParsedTopHits) unitNoGroupBucket.getAggregations().getAsMap().get("unitInfo");
                for (SearchHit hit : unitInfoTopHits.getHits().getHits()) {
                    QueryUnitNoRespVO queryUnitNoRespVO = JSONObject.parseObject(hit.getSourceAsString(), QueryUnitNoRespVO.class);
                    respVOS.add(queryUnitNoRespVO);
                }
            });
        } catch (Exception e) {
            log.error("动态加载单元选项卡查询报错！", e);
            throw new RuntimeException(e);
        }

        return respVOS;
    }

    //ES查询条件封装
    BoolQueryBuilder addRoomFilter(BoolQueryBuilder queryBuilder, RoomelQueryReqVO roomelQueryReqVO) {
        // 状态为未停用
        if (ObjectUtil.isEmpty(roomelQueryReqVO.getReturnMainRoom()) || !roomelQueryReqVO.getReturnMainRoom()) {
            queryBuilder.must(QueryBuilders.termQuery(IsStop, false));
        }

        if (ObjectUtil.isNotEmpty(roomelQueryReqVO.getQflag()) && roomelQueryReqVO.getQflag()) {
            QueryBuilder queryBuilder10 = QueryBuilders.termQuery("isConcentrated", true);
            queryBuilder.must(queryBuilder10);
        } else if (ObjectUtil.isNotEmpty(roomelQueryReqVO.getQflag()) && !roomelQueryReqVO.getQflag()) {
            QueryBuilder queryBuilder10 = QueryBuilders.termQuery("isConcentrated", false);
            queryBuilder.must(queryBuilder10);
            // 分散式只查询整租 or 合租的子房间
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.should(QueryBuilders.termQuery("isWhole", true));
            BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();

            BoolQueryBuilder boolQueryBuilder3 = new BoolQueryBuilder();
            boolQueryBuilder3.must(QueryBuilders.termQuery("isWhole", false));
            if (ObjectUtil.isNotEmpty(roomelQueryReqVO.getReturnMainRoom()) && roomelQueryReqVO.getReturnMainRoom()){
                // 只返回分散式房源的主房间
                boolQueryBuilder3.mustNot(QueryBuilders.existsQuery("superId"));
            }else{
                boolQueryBuilder3.must(QueryBuilders.existsQuery("superId"));
            }
            boolQueryBuilder2.must(boolQueryBuilder3);

            BoolQueryBuilder boolQueryBuilder5 = new BoolQueryBuilder();
            boolQueryBuilder5.mustNot(QueryBuilders.termQuery("roomType.keyword", RoomTypeEnum.GGQY.getValue()));
            boolQueryBuilder2.must(boolQueryBuilder5);
            boolQueryBuilder.should(boolQueryBuilder2);

            queryBuilder.must(boolQueryBuilder);
        } else if (ObjectUtil.isEmpty(roomelQueryReqVO.getQflag())) {
            // 查询整租 or 合租的子房间
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.should(QueryBuilders.termQuery("isWhole", true));
            BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();

            BoolQueryBuilder boolQueryBuilder3 = new BoolQueryBuilder();
            boolQueryBuilder3.must(QueryBuilders.termQuery("isWhole", false));
            if (ObjectUtil.isNotEmpty(roomelQueryReqVO.getReturnMainRoom()) && roomelQueryReqVO.getReturnMainRoom()){
                // 只返回分散式房源的主房间
                boolQueryBuilder3.mustNot(QueryBuilders.existsQuery("superId"));
            }else{
                boolQueryBuilder3.must(QueryBuilders.existsQuery("superId"));
            }
            boolQueryBuilder2.must(boolQueryBuilder3);

            BoolQueryBuilder boolQueryBuilder5 = new BoolQueryBuilder();
            boolQueryBuilder5.mustNot(QueryBuilders.termQuery("roomType.keyword", RoomTypeEnum.GGQY.getValue()));
            boolQueryBuilder2.must(boolQueryBuilder5);
            boolQueryBuilder.should(boolQueryBuilder2);

            queryBuilder.must(boolQueryBuilder);
        }

        //是否锁定
        if (ObjectUtil.isNotEmpty(roomelQueryReqVO.getIsLock())) {
            QueryBuilder queryBuilder10 = QueryBuilders.termQuery("isLock", roomelQueryReqVO.getIsLock());
            queryBuilder.must(queryBuilder10);
        }

        //公共小区id
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getRoomAreaId())) {
            QueryBuilder queryBuilder10 = QueryBuilders.termQuery("roomAreaId", roomelQueryReqVO.getRoomAreaId());
            queryBuilder.must(queryBuilder10);
        }

        //小区名
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getApartmentAreaName())) {
            QueryBuilder queryBuilder10 = QueryBuilders.wildcardQuery("apartmentAreaName.keyword", "*" + roomelQueryReqVO.getApartmentAreaName() + "*");
            queryBuilder.must(queryBuilder10);
        }

        //小区id
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getApartmentAreaId())) {
            QueryBuilder queryBuilder10 = QueryBuilders.termQuery("apartmentAreaId", roomelQueryReqVO.getApartmentAreaId());
            queryBuilder.must(queryBuilder10);
        }

        //公寓id
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getApartmentId())) {
            QueryBuilder queryBuilder11 = QueryBuilders.termQuery("apartmentId", roomelQueryReqVO.getApartmentId());
            queryBuilder.must(queryBuilder11);
        } else {
            //拼接部门权限
            queryBuilder = dataPermissionRule.permission(queryBuilder, "deptId");
        }
        //楼栋号
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getBuildingNo())) {
            QueryBuilder queryBuilder12 = QueryBuilders.matchQuery("buildingNo", roomelQueryReqVO.getBuildingNo());
            queryBuilder.must(queryBuilder12);
        }
        //单元号
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getUnitNo())) {
            QueryBuilder unitNoQuery = QueryBuilders.matchQuery("unitNo", roomelQueryReqVO.getUnitNo());
            queryBuilder.must(unitNoQuery);
        }
        //楼层号
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getFloorNo())) {
            QueryBuilder queryBuilder13 = QueryBuilders.matchQuery("floorNo", roomelQueryReqVO.getFloorNo());
            queryBuilder.must(queryBuilder13);
        }
        // 户型
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getRoomHouseTypeId())) {
            QueryBuilder queryBuildertype1 = QueryBuilders.termQuery("roomHouseTypeId", roomelQueryReqVO.getRoomHouseTypeId());
            queryBuilder.must(queryBuildertype1);
        }
        // 房型
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getLayoutId())) {
            QueryBuilder queryBuildertype2 = QueryBuilders.termQuery("layoutId", roomelQueryReqVO.getLayoutId());
            queryBuilder.must(queryBuildertype2);
        }

        //房态
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getHouseState())) {
            QueryBuilder queryBuilderhousestate = QueryBuilders.termQuery("houseState", roomelQueryReqVO.getHouseState());
            queryBuilder.must(queryBuilderhousestate);
        }

        //房源类型
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getRoomUsage())) {
            QueryBuilder queryBuilderRoomUsage = QueryBuilders.termQuery("roomUsage", roomelQueryReqVO.getRoomUsage());
            queryBuilder.must(queryBuilderRoomUsage);
        }

        //房间名
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getRoomHouseName())) {
            QueryBuilder queryBuilderhousestate = QueryBuilders.matchQuery("roomHouseName", roomelQueryReqVO.getRoomHouseName());
            queryBuilder.must(queryBuilderhousestate);
        }

        //id
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getId())) {
            QueryBuilder idQueryBuilder = QueryBuilders.termQuery("id", roomelQueryReqVO.getId());
            queryBuilder.must(idQueryBuilder);
        }

        //存在租住人信息
        if(ObjectUtil.isNotEmpty(roomelQueryReqVO.getIsHasContractInfo()) && roomelQueryReqVO.getIsHasContractInfo()){
            queryBuilder.must(QueryBuilders.existsQuery("contractInfo"));
        }

        //是否净房
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getIsClean())) {
            QueryBuilder query = QueryBuilders.termQuery("isClean", roomelQueryReqVO.getIsClean());
            queryBuilder.must(query);
        }

        //是否维修房
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getIsRepair())) {
            QueryBuilder query = QueryBuilders.termQuery("isRepair", roomelQueryReqVO.getIsRepair());
            queryBuilder.must(query);
        }


        //搜索框-分词搜索-房间号、房源编码、租客姓名、租客手机号
        if (!ObjectUtil.isEmpty(roomelQueryReqVO.getSearchbox())) {
            roomelQueryReqVO.setSearchbox(roomelQueryReqVO.getSearchbox().trim());
            //QueryBuilder queryBuilderbox = QueryBuilders.multiMatchQuery(roomelQueryReqVO.getSearchbox(), "roomHouseName", "tenantinfo", "apartmentAreaName", "buildingNo").analyzer(Analyzer.ik_max_word.name());
            BoolQueryBuilder should = QueryBuilders.boolQuery()
                    .should(QueryBuilders.wildcardQuery("fullName" + ".keyword", "*" + roomelQueryReqVO.getSearchbox() + "*"))
                    .should(QueryBuilders.wildcardQuery("tenantinfo" + ".keyword", "*" + roomelQueryReqVO.getSearchbox() + "*"));
            queryBuilder.must(should);
        }

        return queryBuilder;
    }


}
